Skip to content

chore: Simplifying SortPreservingMergeStream to use generators instead of state machine#23407

Merged
rluvaton merged 26 commits into
apache:mainfrom
rluvaton:use-yield
Jul 15, 2026
Merged

chore: Simplifying SortPreservingMergeStream to use generators instead of state machine#23407
rluvaton merged 26 commits into
apache:mainfrom
rluvaton:use-yield

Conversation

@rluvaton

@rluvaton rluvaton commented Jul 9, 2026

Copy link
Copy Markdown
Member

Which issue does this PR close?

  • N/A

Rationale for this change

I'm trying to make some Sort optimization but it is hard to get stuff merged where the code is already complex even if adding a simple optimization (like when only 1 stream is left just return those batches).

This makes the code simpler as you can now read it in straight line flow control, while not sacrificing performance

I did not use RecordBatchReceiverStreamBuilder since I want pull based and not push based stream

What changes are included in this PR?

Added genawaiter dependency, replace the SortPersevingMergeStream main state machine loop with generator yield

Are these changes tested?

existing tests

Are there any user-facing changes?

no


Why not using async-stream crate from tokio?

Why not using async-stream crate from tokio (that we already have transitive dependency on) or other crates that are macro based.

Because couple of reasons:

  1. cargo fmt does not format macros body, so you manually need to format and validate that the style is kept
  2. more "magic" yield is not a function call
    i. When you read the code, you cant go to definition of the yield keyword since it is not a function
    ii. Cant put debugger on that keyword (from what I remember)
    iii. there is some hidden code that you need to
  3. You can only use yield from the macro body (so you cant extract functions with yield for example)

@github-actions github-actions Bot added the physical-plan Changes to the physical-plan crate label Jul 9, 2026
@rluvaton

rluvaton commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

run benchmarks

@rluvaton

rluvaton commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

run benchmark sort tpch10

@apache apache deleted a comment from adriangbot Jul 9, 2026
@apache apache deleted a comment from adriangbot Jul 9, 2026
@apache apache deleted a comment from adriangbot Jul 9, 2026
@apache apache deleted a comment from adriangbot Jul 9, 2026
@apache apache deleted a comment from adriangbot Jul 9, 2026
@apache apache deleted a comment from adriangbot Jul 9, 2026
@apache apache deleted a comment from adriangbot Jul 9, 2026
@apache apache deleted a comment from adriangbot Jul 9, 2026
@apache apache deleted a comment from adriangbot Jul 9, 2026
@apache apache deleted a comment from adriangbot Jul 9, 2026
@adriangbot

This comment was marked as outdated.

@adriangbot

This comment was marked as outdated.

@adriangbot

This comment was marked as outdated.

@adriangbot

This comment was marked as outdated.

@adriangbot

This comment was marked as outdated.

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and use-yield
--------------------
Benchmark tpch_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Query     ┃                           HEAD ┃                      use-yield ┃    Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ QQuery 1  │ 38.84 / 39.98 ±1.06 / 41.70 ms │ 38.56 / 40.32 ±1.44 / 41.87 ms │ no change │
│ QQuery 2  │ 19.82 / 20.00 ±0.18 / 20.30 ms │ 19.06 / 19.47 ±0.35 / 20.13 ms │ no change │
│ QQuery 3  │ 31.27 / 34.73 ±2.04 / 36.74 ms │ 31.68 / 34.51 ±1.80 / 37.29 ms │ no change │
│ QQuery 4  │ 17.69 / 17.95 ±0.43 / 18.81 ms │ 17.58 / 17.79 ±0.13 / 17.94 ms │ no change │
│ QQuery 5  │ 38.29 / 40.52 ±1.18 / 41.60 ms │ 38.28 / 40.33 ±2.03 / 44.00 ms │ no change │
│ QQuery 6  │ 16.20 / 16.94 ±0.76 / 18.33 ms │ 16.17 / 16.25 ±0.07 / 16.37 ms │ no change │
│ QQuery 7  │ 45.51 / 47.50 ±2.46 / 51.80 ms │ 45.07 / 46.43 ±1.02 / 47.91 ms │ no change │
│ QQuery 8  │ 43.06 / 43.82 ±1.13 / 46.06 ms │ 43.66 / 43.89 ±0.26 / 44.40 ms │ no change │
│ QQuery 9  │ 49.98 / 50.83 ±0.62 / 51.60 ms │ 49.72 / 50.76 ±0.79 / 51.82 ms │ no change │
│ QQuery 10 │ 42.43 / 42.56 ±0.14 / 42.75 ms │ 42.25 / 42.65 ±0.23 / 42.88 ms │ no change │
│ QQuery 11 │ 13.54 / 14.21 ±0.79 / 15.65 ms │ 13.35 / 13.53 ±0.11 / 13.65 ms │ no change │
│ QQuery 12 │ 23.82 / 24.41 ±0.52 / 25.16 ms │ 24.23 / 24.77 ±0.39 / 25.35 ms │ no change │
│ QQuery 13 │ 31.61 / 34.28 ±2.44 / 37.27 ms │ 32.55 / 34.69 ±1.79 / 36.80 ms │ no change │
│ QQuery 14 │ 23.81 / 24.14 ±0.24 / 24.34 ms │ 24.12 / 24.18 ±0.04 / 24.23 ms │ no change │
│ QQuery 15 │ 31.36 / 31.57 ±0.25 / 31.95 ms │ 31.27 / 32.22 ±0.98 / 33.53 ms │ no change │
│ QQuery 16 │ 14.01 / 14.26 ±0.17 / 14.54 ms │ 14.26 / 14.46 ±0.20 / 14.79 ms │ no change │
│ QQuery 17 │ 73.88 / 75.40 ±0.98 / 76.96 ms │ 74.88 / 76.14 ±1.33 / 78.51 ms │ no change │
│ QQuery 18 │ 59.14 / 60.82 ±1.28 / 63.06 ms │ 60.30 / 61.34 ±0.81 / 62.47 ms │ no change │
│ QQuery 19 │ 33.04 / 33.61 ±0.65 / 34.79 ms │ 33.52 / 33.81 ±0.31 / 34.25 ms │ no change │
│ QQuery 20 │ 32.41 / 33.35 ±0.88 / 34.74 ms │ 31.79 / 32.34 ±0.37 / 32.88 ms │ no change │
│ QQuery 21 │ 55.61 / 56.94 ±1.08 / 58.81 ms │ 55.24 / 56.42 ±1.04 / 57.72 ms │ no change │
│ QQuery 22 │ 14.08 / 14.23 ±0.12 / 14.40 ms │ 13.93 / 14.26 ±0.23 / 14.50 ms │ no change │
└───────────┴────────────────────────────────┴────────────────────────────────┴───────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Benchmark Summary        ┃          ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩
│ Total Time (HEAD)        │ 772.05ms │
│ Total Time (use-yield)   │ 770.56ms │
│ Average Time (HEAD)      │  35.09ms │
│ Average Time (use-yield) │  35.03ms │
│ Queries Faster           │        0 │
│ Queries Slower           │        0 │
│ Queries with No Change   │       22 │
│ Queries with Failure     │        0 │
└──────────────────────────┴──────────┘

Resource Usage

tpch — base (merge-base)

Metric Value
Wall time 5.0s
Peak memory 1.2 GiB
Avg memory 516.1 MiB
CPU user 22.4s
CPU sys 1.8s
Peak spill 0 B

tpch — branch

Metric Value
Wall time 5.0s
Peak memory 1.1 GiB
Avg memory 500.1 MiB
CPU user 22.4s
CPU sys 1.7s
Peak spill 0 B

File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and use-yield
--------------------
Benchmark tpch_sf10.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃                               HEAD ┃                          use-yield ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 1  │  311.25 / 312.79 ±1.35 / 315.14 ms │  311.77 / 316.62 ±3.59 / 321.53 ms │     no change │
│ QQuery 2  │  101.33 / 105.25 ±4.17 / 112.99 ms │  101.35 / 105.03 ±1.91 / 106.70 ms │     no change │
│ QQuery 3  │  231.46 / 237.92 ±5.38 / 244.72 ms │  228.14 / 232.63 ±3.22 / 237.76 ms │     no change │
│ QQuery 4  │  111.72 / 112.15 ±0.44 / 112.94 ms │  111.49 / 114.67 ±1.81 / 117.04 ms │     no change │
│ QQuery 5  │  349.33 / 357.73 ±8.49 / 372.02 ms │ 352.62 / 377.10 ±16.61 / 395.92 ms │  1.05x slower │
│ QQuery 6  │  123.63 / 125.12 ±1.34 / 127.66 ms │  129.85 / 135.94 ±5.43 / 146.05 ms │  1.09x slower │
│ QQuery 7  │ 497.86 / 525.50 ±16.16 / 543.33 ms │ 457.15 / 477.22 ±15.20 / 504.14 ms │ +1.10x faster │
│ QQuery 8  │ 407.49 / 418.73 ±10.04 / 432.96 ms │  378.92 / 387.85 ±6.99 / 399.30 ms │ +1.08x faster │
│ QQuery 9  │ 555.62 / 589.30 ±29.53 / 628.61 ms │  540.35 / 553.34 ±9.66 / 565.46 ms │ +1.06x faster │
│ QQuery 10 │  290.39 / 302.72 ±6.63 / 308.43 ms │  289.88 / 297.10 ±5.34 / 305.38 ms │     no change │
│ QQuery 11 │     83.01 / 88.47 ±4.05 / 94.40 ms │    85.34 / 89.25 ±5.44 / 100.05 ms │     no change │
│ QQuery 12 │  178.16 / 187.41 ±9.20 / 199.59 ms │  176.07 / 182.94 ±6.89 / 192.42 ms │     no change │
│ QQuery 13 │  289.93 / 293.86 ±5.59 / 304.93 ms │ 292.87 / 313.18 ±12.09 / 327.28 ms │  1.07x slower │
│ QQuery 14 │  170.67 / 174.69 ±4.08 / 182.46 ms │  184.52 / 190.32 ±5.74 / 199.97 ms │  1.09x slower │
│ QQuery 15 │  300.43 / 303.15 ±2.25 / 306.40 ms │  302.13 / 314.46 ±9.93 / 329.40 ms │     no change │
│ QQuery 16 │     63.57 / 68.44 ±5.87 / 78.75 ms │     64.09 / 67.22 ±2.88 / 72.14 ms │     no change │
│ QQuery 17 │ 619.55 / 690.79 ±55.70 / 755.96 ms │  616.61 / 626.05 ±6.93 / 637.00 ms │ +1.10x faster │
│ QQuery 18 │ 680.67 / 698.70 ±11.25 / 711.83 ms │ 656.85 / 691.63 ±21.82 / 723.49 ms │     no change │
│ QQuery 19 │ 245.94 / 261.52 ±12.22 / 275.61 ms │ 242.24 / 257.32 ±14.78 / 278.12 ms │     no change │
│ QQuery 20 │ 275.13 / 289.26 ±10.86 / 302.85 ms │ 273.47 / 290.23 ±12.17 / 305.17 ms │     no change │
│ QQuery 21 │  655.50 / 661.04 ±3.26 / 665.29 ms │ 667.99 / 728.99 ±30.59 / 748.30 ms │  1.10x slower │
│ QQuery 22 │     60.16 / 61.41 ±1.58 / 64.47 ms │     66.91 / 71.62 ±4.83 / 80.91 ms │  1.17x slower │
└───────────┴────────────────────────────────────┴────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ Benchmark Summary        ┃           ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ Total Time (HEAD)        │ 6865.97ms │
│ Total Time (use-yield)   │ 6820.72ms │
│ Average Time (HEAD)      │  312.09ms │
│ Average Time (use-yield) │  310.03ms │
│ Queries Faster           │         4 │
│ Queries Slower           │         6 │
│ Queries with No Change   │        12 │
│ Queries with Failure     │         0 │
└──────────────────────────┴───────────┘

Resource Usage

tpch10 — base (merge-base)

Metric Value
Wall time 35.0s
Peak memory 4.9 GiB
Avg memory 1.5 GiB
CPU user 347.8s
CPU sys 18.1s
Peak spill 0 B

tpch10 — branch

Metric Value
Wall time 35.0s
Peak memory 5.1 GiB
Avg memory 1.5 GiB
CPU user 345.9s
CPU sys 18.7s
Peak spill 0 B

File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and use-yield
--------------------
Benchmark tpcds_sf1.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃                                  HEAD ┃                              use-yield ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 1  │           6.22 / 6.72 ±0.75 / 8.21 ms │            5.89 / 6.46 ±0.83 / 8.09 ms │     no change │
│ QQuery 2  │        84.59 / 85.72 ±0.57 / 86.08 ms │         83.05 / 83.39 ±0.29 / 83.91 ms │     no change │
│ QQuery 3  │        32.04 / 32.27 ±0.17 / 32.48 ms │         31.14 / 31.58 ±0.38 / 32.07 ms │     no change │
│ QQuery 4  │    506.19 / 524.13 ±21.41 / 564.25 ms │      551.14 / 557.33 ±5.08 / 562.94 ms │  1.06x slower │
│ QQuery 5  │        51.96 / 52.75 ±0.47 / 53.40 ms │         53.44 / 54.44 ±0.55 / 54.98 ms │     no change │
│ QQuery 6  │        36.72 / 37.26 ±0.39 / 37.60 ms │         38.40 / 38.61 ±0.15 / 38.86 ms │     no change │
│ QQuery 7  │       96.31 / 98.88 ±3.29 / 105.11 ms │       98.20 / 104.69 ±3.26 / 106.80 ms │  1.06x slower │
│ QQuery 8  │        37.21 / 37.67 ±0.38 / 38.12 ms │         40.58 / 41.20 ±0.66 / 42.35 ms │  1.09x slower │
│ QQuery 9  │        52.78 / 56.19 ±1.82 / 58.00 ms │         58.81 / 60.38 ±1.28 / 62.20 ms │  1.07x slower │
│ QQuery 10 │        64.39 / 64.81 ±0.45 / 65.64 ms │         68.51 / 71.71 ±2.53 / 76.19 ms │  1.11x slower │
│ QQuery 11 │     316.40 / 322.79 ±4.87 / 331.23 ms │     354.56 / 368.03 ±10.90 / 383.23 ms │  1.14x slower │
│ QQuery 12 │        29.37 / 29.83 ±0.79 / 31.41 ms │         32.19 / 33.12 ±0.84 / 34.52 ms │  1.11x slower │
│ QQuery 13 │     121.17 / 123.76 ±4.11 / 131.88 ms │      123.68 / 125.41 ±1.49 / 127.97 ms │     no change │
│ QQuery 14 │     419.72 / 423.01 ±1.72 / 424.68 ms │      429.64 / 434.54 ±2.94 / 437.66 ms │     no change │
│ QQuery 15 │        59.66 / 60.39 ±0.74 / 61.69 ms │         65.70 / 67.77 ±2.47 / 72.44 ms │  1.12x slower │
│ QQuery 16 │           6.80 / 6.95 ±0.19 / 7.32 ms │            7.08 / 7.24 ±0.11 / 7.38 ms │     no change │
│ QQuery 17 │        81.29 / 82.56 ±1.32 / 84.78 ms │         83.61 / 85.20 ±1.90 / 88.90 ms │     no change │
│ QQuery 18 │     125.77 / 127.29 ±0.95 / 128.66 ms │      131.92 / 134.49 ±1.96 / 137.89 ms │  1.06x slower │
│ QQuery 19 │        42.54 / 43.58 ±1.37 / 46.27 ms │         44.33 / 44.94 ±0.52 / 45.73 ms │     no change │
│ QQuery 20 │        37.26 / 38.01 ±0.80 / 39.55 ms │         38.08 / 39.03 ±0.89 / 40.62 ms │     no change │
│ QQuery 21 │        18.11 / 18.29 ±0.20 / 18.58 ms │         18.95 / 19.55 ±0.89 / 21.32 ms │  1.07x slower │
│ QQuery 22 │        63.32 / 63.97 ±0.41 / 64.40 ms │         68.09 / 70.55 ±1.26 / 71.58 ms │  1.10x slower │
│ QQuery 23 │     353.02 / 356.66 ±2.07 / 358.48 ms │      381.17 / 388.99 ±7.38 / 400.08 ms │  1.09x slower │
│ QQuery 24 │     228.07 / 233.93 ±5.17 / 242.14 ms │      237.72 / 239.83 ±2.81 / 245.38 ms │     no change │
│ QQuery 25 │     119.93 / 122.64 ±1.75 / 124.53 ms │      117.58 / 119.56 ±2.14 / 123.49 ms │     no change │
│ QQuery 26 │        62.55 / 63.35 ±0.43 / 63.70 ms │         60.91 / 62.46 ±2.35 / 67.07 ms │     no change │
│ QQuery 27 │           7.21 / 7.36 ±0.09 / 7.47 ms │            6.86 / 7.02 ±0.09 / 7.14 ms │     no change │
│ QQuery 28 │        60.78 / 64.49 ±1.88 / 65.83 ms │         60.59 / 64.57 ±2.06 / 66.39 ms │     no change │
│ QQuery 29 │      99.94 / 104.33 ±4.66 / 112.57 ms │      102.33 / 104.18 ±1.44 / 106.68 ms │     no change │
│ QQuery 30 │        32.80 / 33.02 ±0.25 / 33.50 ms │         35.29 / 37.07 ±2.03 / 40.94 ms │  1.12x slower │
│ QQuery 31 │     114.57 / 117.92 ±2.70 / 121.55 ms │      118.42 / 120.08 ±1.21 / 121.33 ms │     no change │
│ QQuery 32 │        22.05 / 22.49 ±0.36 / 22.94 ms │         22.69 / 22.78 ±0.08 / 22.91 ms │     no change │
│ QQuery 33 │        39.15 / 39.49 ±0.23 / 39.83 ms │         40.10 / 40.30 ±0.22 / 40.58 ms │     no change │
│ QQuery 34 │        10.44 / 10.65 ±0.20 / 10.99 ms │         11.17 / 12.87 ±2.67 / 18.18 ms │  1.21x slower │
│ QQuery 35 │        74.33 / 76.66 ±1.69 / 78.43 ms │         79.58 / 81.24 ±1.07 / 82.53 ms │  1.06x slower │
│ QQuery 36 │           5.92 / 6.10 ±0.19 / 6.45 ms │            6.33 / 6.45 ±0.10 / 6.64 ms │  1.06x slower │
│ QQuery 37 │           7.09 / 7.19 ±0.07 / 7.26 ms │            7.52 / 7.63 ±0.07 / 7.72 ms │  1.06x slower │
│ QQuery 38 │        64.43 / 65.20 ±0.62 / 66.24 ms │         68.35 / 69.24 ±0.95 / 70.90 ms │  1.06x slower │
│ QQuery 39 │        91.82 / 92.30 ±0.37 / 92.79 ms │      100.21 / 112.82 ±7.07 / 121.77 ms │  1.22x slower │
│ QQuery 40 │        24.13 / 24.29 ±0.14 / 24.51 ms │         26.50 / 27.04 ±0.43 / 27.63 ms │  1.11x slower │
│ QQuery 41 │        11.79 / 11.96 ±0.14 / 12.20 ms │         13.74 / 14.11 ±0.23 / 14.43 ms │  1.18x slower │
│ QQuery 42 │        24.92 / 26.43 ±1.90 / 29.94 ms │         27.64 / 28.18 ±0.39 / 28.69 ms │  1.07x slower │
│ QQuery 43 │           4.97 / 5.15 ±0.19 / 5.52 ms │            5.82 / 6.07 ±0.21 / 6.38 ms │  1.18x slower │
│ QQuery 44 │           9.59 / 9.71 ±0.12 / 9.87 ms │         11.44 / 11.66 ±0.18 / 11.98 ms │  1.20x slower │
│ QQuery 45 │        39.59 / 40.18 ±0.47 / 40.97 ms │         56.01 / 58.29 ±1.84 / 61.36 ms │  1.45x slower │
│ QQuery 46 │        12.08 / 12.49 ±0.31 / 12.93 ms │         14.09 / 14.55 ±0.48 / 15.16 ms │  1.16x slower │
│ QQuery 47 │     234.62 / 237.55 ±2.27 / 240.43 ms │     262.41 / 279.04 ±17.71 / 313.02 ms │  1.17x slower │
│ QQuery 48 │        97.39 / 97.98 ±0.34 / 98.35 ms │      101.06 / 105.21 ±5.04 / 114.98 ms │  1.07x slower │
│ QQuery 49 │        78.43 / 80.35 ±2.83 / 85.90 ms │         80.12 / 82.33 ±1.65 / 84.42 ms │     no change │
│ QQuery 50 │        59.90 / 60.67 ±0.54 / 61.41 ms │         62.56 / 63.74 ±0.85 / 64.73 ms │  1.05x slower │
│ QQuery 51 │        93.63 / 94.61 ±0.70 / 95.77 ms │        96.79 / 99.32 ±2.03 / 101.73 ms │     no change │
│ QQuery 52 │        25.18 / 25.42 ±0.22 / 25.69 ms │         25.45 / 25.98 ±0.37 / 26.51 ms │     no change │
│ QQuery 53 │        30.17 / 30.36 ±0.13 / 30.52 ms │         30.84 / 31.68 ±1.06 / 33.74 ms │     no change │
│ QQuery 54 │        56.81 / 57.42 ±0.33 / 57.79 ms │         58.18 / 58.58 ±0.30 / 59.05 ms │     no change │
│ QQuery 55 │        24.26 / 24.63 ±0.35 / 25.26 ms │         24.83 / 26.49 ±2.37 / 31.12 ms │  1.08x slower │
│ QQuery 56 │        39.93 / 41.45 ±1.70 / 44.66 ms │         41.25 / 41.53 ±0.23 / 41.81 ms │     no change │
│ QQuery 57 │     178.09 / 180.34 ±1.41 / 181.84 ms │      186.52 / 191.42 ±3.02 / 195.59 ms │  1.06x slower │
│ QQuery 58 │     117.36 / 119.34 ±1.98 / 123.11 ms │      122.30 / 123.96 ±1.71 / 126.41 ms │     no change │
│ QQuery 59 │     119.90 / 121.61 ±2.49 / 126.55 ms │      121.68 / 122.94 ±1.56 / 126.00 ms │     no change │
│ QQuery 60 │        40.42 / 41.44 ±0.78 / 42.77 ms │         41.59 / 42.76 ±0.78 / 43.75 ms │     no change │
│ QQuery 61 │        12.32 / 12.76 ±0.39 / 13.43 ms │         12.95 / 13.12 ±0.12 / 13.32 ms │     no change │
│ QQuery 62 │        47.44 / 47.62 ±0.15 / 47.85 ms │         48.07 / 48.50 ±0.25 / 48.75 ms │     no change │
│ QQuery 63 │        30.10 / 30.33 ±0.15 / 30.55 ms │         31.04 / 32.53 ±2.06 / 36.61 ms │  1.07x slower │
│ QQuery 64 │     414.79 / 419.32 ±2.85 / 422.22 ms │      436.57 / 440.22 ±5.49 / 450.98 ms │     no change │
│ QQuery 65 │     149.99 / 154.50 ±3.01 / 158.83 ms │      151.23 / 155.55 ±2.58 / 158.26 ms │     no change │
│ QQuery 66 │        81.35 / 83.75 ±2.32 / 88.00 ms │         84.58 / 85.08 ±0.27 / 85.33 ms │     no change │
│ QQuery 67 │     248.41 / 252.96 ±4.73 / 261.27 ms │      272.04 / 275.23 ±2.68 / 278.11 ms │  1.09x slower │
│ QQuery 68 │        12.01 / 12.22 ±0.21 / 12.54 ms │         12.72 / 12.87 ±0.11 / 13.01 ms │  1.05x slower │
│ QQuery 69 │        58.54 / 58.77 ±0.20 / 59.07 ms │         59.75 / 62.50 ±3.07 / 68.40 ms │  1.06x slower │
│ QQuery 70 │     108.77 / 114.01 ±5.57 / 120.98 ms │      111.49 / 114.10 ±3.33 / 120.66 ms │     no change │
│ QQuery 71 │        36.97 / 37.38 ±0.38 / 37.89 ms │         37.31 / 37.75 ±0.30 / 38.04 ms │     no change │
│ QQuery 72 │ 2286.96 / 2413.27 ±82.04 / 2506.98 ms │ 2381.75 / 2617.29 ±134.92 / 2777.96 ms │  1.08x slower │
│ QQuery 73 │        10.38 / 10.57 ±0.20 / 10.86 ms │         10.89 / 11.37 ±0.35 / 11.94 ms │  1.08x slower │
│ QQuery 74 │    179.56 / 192.29 ±10.07 / 203.29 ms │      198.38 / 207.62 ±9.10 / 220.04 ms │  1.08x slower │
│ QQuery 75 │     152.84 / 155.05 ±2.19 / 158.27 ms │      158.07 / 160.75 ±1.60 / 162.53 ms │     no change │
│ QQuery 76 │        36.58 / 37.21 ±0.57 / 38.10 ms │         38.75 / 39.56 ±0.65 / 40.45 ms │  1.06x slower │
│ QQuery 77 │        61.89 / 62.38 ±0.32 / 62.86 ms │         66.81 / 67.75 ±0.72 / 68.85 ms │  1.09x slower │
│ QQuery 78 │     200.31 / 205.02 ±3.78 / 209.61 ms │      212.76 / 217.59 ±4.69 / 224.17 ms │  1.06x slower │
│ QQuery 79 │        69.26 / 71.03 ±2.67 / 76.29 ms │         70.36 / 71.39 ±0.71 / 72.32 ms │     no change │
│ QQuery 80 │     106.83 / 110.26 ±2.50 / 112.97 ms │      104.90 / 109.21 ±7.23 / 123.63 ms │     no change │
│ QQuery 81 │        27.84 / 28.71 ±0.66 / 29.56 ms │         28.02 / 29.29 ±2.23 / 33.74 ms │     no change │
│ QQuery 82 │        18.73 / 20.23 ±2.16 / 24.38 ms │         17.63 / 18.03 ±0.27 / 18.39 ms │ +1.12x faster │
│ QQuery 83 │        44.31 / 45.79 ±1.66 / 49.03 ms │         42.23 / 42.92 ±0.75 / 44.38 ms │ +1.07x faster │
│ QQuery 84 │        32.36 / 33.73 ±1.79 / 37.27 ms │         31.44 / 33.29 ±3.16 / 39.58 ms │     no change │
│ QQuery 85 │     113.60 / 115.19 ±1.29 / 117.15 ms │      111.88 / 113.45 ±1.07 / 115.13 ms │     no change │
│ QQuery 86 │        26.35 / 28.25 ±1.30 / 29.84 ms │         28.42 / 29.05 ±0.52 / 29.75 ms │     no change │
│ QQuery 87 │        64.91 / 66.33 ±1.02 / 68.04 ms │         74.53 / 75.83 ±1.21 / 77.80 ms │  1.14x slower │
│ QQuery 88 │        65.10 / 65.77 ±0.77 / 66.96 ms │         68.51 / 68.96 ±0.49 / 69.86 ms │     no change │
│ QQuery 89 │        37.75 / 38.22 ±0.74 / 39.68 ms │         39.45 / 40.30 ±0.91 / 41.82 ms │  1.05x slower │
│ QQuery 90 │        18.30 / 18.44 ±0.11 / 18.57 ms │         19.08 / 19.29 ±0.13 / 19.45 ms │     no change │
│ QQuery 91 │        48.09 / 48.87 ±0.43 / 49.29 ms │         50.63 / 52.20 ±2.76 / 57.70 ms │  1.07x slower │
│ QQuery 92 │        31.26 / 32.65 ±1.22 / 34.84 ms │         33.71 / 34.45 ±0.44 / 34.86 ms │  1.06x slower │
│ QQuery 93 │        51.35 / 52.77 ±0.84 / 54.00 ms │         56.64 / 57.78 ±1.06 / 59.11 ms │  1.09x slower │
│ QQuery 94 │        39.09 / 39.71 ±0.54 / 40.71 ms │         39.82 / 40.47 ±0.69 / 41.32 ms │     no change │
│ QQuery 95 │        83.35 / 85.05 ±1.76 / 87.30 ms │         84.36 / 86.37 ±1.82 / 88.58 ms │     no change │
│ QQuery 96 │        24.64 / 25.08 ±0.30 / 25.41 ms │         25.38 / 25.62 ±0.17 / 25.90 ms │     no change │
│ QQuery 97 │        47.92 / 48.53 ±0.62 / 49.67 ms │         48.80 / 49.48 ±0.61 / 50.58 ms │     no change │
│ QQuery 98 │        43.50 / 44.14 ±0.45 / 44.76 ms │         46.06 / 46.95 ±0.66 / 47.87 ms │  1.06x slower │
│ QQuery 99 │        72.27 / 74.46 ±1.59 / 76.53 ms │         73.00 / 76.01 ±3.28 / 82.17 ms │     no change │
└───────────┴───────────────────────────────────────┴────────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Benchmark Summary        ┃            ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ Total Time (HEAD)        │ 10496.62ms │
│ Total Time (use-yield)   │ 11151.34ms │
│ Average Time (HEAD)      │   106.03ms │
│ Average Time (use-yield) │   112.64ms │
│ Queries Faster           │          2 │
│ Queries Slower           │         47 │
│ Queries with No Change   │         50 │
│ Queries with Failure     │          0 │
└──────────────────────────┴────────────┘

Resource Usage

tpcds — base (merge-base)

Metric Value
Wall time 55.0s
Peak memory 2.3 GiB
Avg memory 1.6 GiB
CPU user 242.3s
CPU sys 6.2s
Peak spill 0 B

tpcds — branch

Metric Value
Wall time 60.0s
Peak memory 2.0 GiB
Avg memory 1.4 GiB
CPU user 260.9s
CPU sys 6.8s
Peak spill 0 B

File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

Comparing HEAD and use-yield
--------------------
Benchmark clickbench_partitioned.json
--------------------
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Query     ┃                                  HEAD ┃                             use-yield ┃        Change ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ QQuery 0  │          1.27 / 4.27 ±5.77 / 15.81 ms │          1.48 / 4.55 ±5.93 / 16.41 ms │  1.07x slower │
│ QQuery 1  │        13.14 / 13.73 ±0.32 / 14.05 ms │        14.06 / 14.37 ±0.26 / 14.73 ms │     no change │
│ QQuery 2  │        36.94 / 37.37 ±0.34 / 37.91 ms │        37.97 / 38.28 ±0.26 / 38.71 ms │     no change │
│ QQuery 3  │        32.05 / 33.86 ±1.49 / 36.47 ms │        31.93 / 33.29 ±0.77 / 34.08 ms │     no change │
│ QQuery 4  │     265.78 / 269.38 ±2.85 / 272.39 ms │     257.97 / 263.92 ±4.70 / 272.13 ms │     no change │
│ QQuery 5  │     302.05 / 308.05 ±4.12 / 313.83 ms │     296.35 / 299.07 ±1.79 / 301.77 ms │     no change │
│ QQuery 6  │           1.30 / 1.64 ±0.25 / 1.89 ms │           1.32 / 1.49 ±0.26 / 2.00 ms │ +1.11x faster │
│ QQuery 7  │        14.59 / 15.14 ±0.63 / 16.37 ms │        15.03 / 15.25 ±0.15 / 15.48 ms │     no change │
│ QQuery 8  │     357.99 / 361.71 ±2.45 / 364.76 ms │     365.47 / 373.15 ±6.01 / 383.71 ms │     no change │
│ QQuery 9  │    501.47 / 517.24 ±14.44 / 541.77 ms │    508.70 / 527.26 ±18.60 / 551.35 ms │     no change │
│ QQuery 10 │        74.06 / 76.79 ±1.68 / 78.77 ms │        76.53 / 82.22 ±8.78 / 99.64 ms │  1.07x slower │
│ QQuery 11 │       89.10 / 93.59 ±6.44 / 106.31 ms │        88.73 / 90.48 ±2.02 / 94.18 ms │     no change │
│ QQuery 12 │     304.89 / 309.62 ±4.42 / 316.01 ms │     303.62 / 312.43 ±7.17 / 324.03 ms │     no change │
│ QQuery 13 │     423.68 / 434.82 ±9.83 / 450.96 ms │    412.74 / 429.08 ±14.23 / 449.27 ms │     no change │
│ QQuery 14 │     320.70 / 331.28 ±7.35 / 340.08 ms │     316.08 / 329.25 ±7.29 / 336.95 ms │     no change │
│ QQuery 15 │     313.82 / 320.00 ±5.62 / 329.81 ms │     308.96 / 313.65 ±2.97 / 316.98 ms │     no change │
│ QQuery 16 │    697.04 / 721.65 ±22.18 / 756.58 ms │    688.88 / 704.79 ±10.80 / 719.10 ms │     no change │
│ QQuery 17 │     719.00 / 728.55 ±5.65 / 734.23 ms │    670.26 / 686.37 ±11.33 / 699.15 ms │ +1.06x faster │
│ QQuery 18 │ 1395.86 / 1414.20 ±16.00 / 1441.78 ms │ 1321.16 / 1367.50 ±26.58 / 1398.47 ms │     no change │
│ QQuery 19 │        29.02 / 30.36 ±0.97 / 31.61 ms │       29.37 / 38.64 ±17.96 / 74.56 ms │  1.27x slower │
│ QQuery 20 │     523.50 / 533.01 ±8.08 / 543.64 ms │     528.67 / 534.28 ±5.15 / 543.51 ms │     no change │
│ QQuery 21 │     518.80 / 527.07 ±6.85 / 537.09 ms │     531.27 / 538.83 ±5.09 / 546.33 ms │     no change │
│ QQuery 22 │  989.70 / 1001.99 ±10.20 / 1016.51 ms │ 1028.32 / 1043.06 ±10.13 / 1056.34 ms │     no change │
│ QQuery 23 │ 3044.57 / 3146.98 ±72.21 / 3231.85 ms │ 3275.40 / 3341.54 ±45.25 / 3400.99 ms │  1.06x slower │
│ QQuery 24 │        42.01 / 47.34 ±6.46 / 56.99 ms │        43.80 / 44.64 ±1.12 / 46.73 ms │ +1.06x faster │
│ QQuery 25 │     113.52 / 120.65 ±8.18 / 135.73 ms │     119.18 / 124.51 ±6.18 / 135.64 ms │     no change │
│ QQuery 26 │        42.75 / 44.00 ±1.49 / 46.83 ms │        43.90 / 45.14 ±1.33 / 47.55 ms │     no change │
│ QQuery 27 │    672.45 / 684.98 ±12.06 / 706.51 ms │     694.30 / 701.62 ±5.58 / 709.35 ms │     no change │
│ QQuery 28 │ 3087.69 / 3108.60 ±27.61 / 3161.52 ms │ 3180.00 / 3199.70 ±19.92 / 3230.88 ms │     no change │
│ QQuery 29 │       41.51 / 53.91 ±21.13 / 96.07 ms │      43.41 / 62.34 ±36.31 / 134.96 ms │  1.16x slower │
│ QQuery 30 │     320.74 / 334.38 ±7.41 / 340.79 ms │     335.64 / 342.29 ±6.11 / 353.84 ms │     no change │
│ QQuery 31 │     296.20 / 307.67 ±6.22 / 314.48 ms │     308.55 / 318.83 ±9.30 / 334.53 ms │     no change │
│ QQuery 32 │ 1002.01 / 1058.87 ±41.16 / 1117.65 ms │ 1071.77 / 1092.90 ±21.93 / 1120.30 ms │     no change │
│ QQuery 33 │ 1597.79 / 1626.57 ±21.18 / 1661.88 ms │ 1558.43 / 1626.80 ±81.32 / 1769.12 ms │     no change │
│ QQuery 34 │ 1671.60 / 1723.91 ±31.49 / 1761.65 ms │ 1554.01 / 1617.88 ±51.98 / 1699.48 ms │ +1.07x faster │
│ QQuery 35 │    343.44 / 356.74 ±15.62 / 387.38 ms │    314.92 / 328.14 ±14.70 / 356.71 ms │ +1.09x faster │
│ QQuery 36 │        71.54 / 78.90 ±6.23 / 87.34 ms │        70.21 / 76.82 ±5.80 / 87.34 ms │     no change │
│ QQuery 37 │        38.29 / 40.67 ±4.49 / 49.64 ms │        37.30 / 38.49 ±1.38 / 40.99 ms │ +1.06x faster │
│ QQuery 38 │        41.58 / 46.44 ±2.88 / 49.86 ms │        41.56 / 44.66 ±3.74 / 50.49 ms │     no change │
│ QQuery 39 │     152.28 / 170.08 ±9.51 / 179.33 ms │     164.10 / 168.36 ±5.09 / 178.13 ms │     no change │
│ QQuery 40 │        15.61 / 17.30 ±2.75 / 22.71 ms │        15.14 / 15.42 ±0.20 / 15.74 ms │ +1.12x faster │
│ QQuery 41 │        14.98 / 18.34 ±3.88 / 24.15 ms │       15.44 / 23.70 ±10.01 / 43.00 ms │  1.29x slower │
│ QQuery 42 │        14.32 / 14.97 ±1.17 / 17.30 ms │        14.52 / 16.23 ±2.92 / 22.05 ms │  1.08x slower │
└───────────┴───────────────────────────────────────┴───────────────────────────────────────┴───────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Benchmark Summary        ┃            ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ Total Time (HEAD)        │ 21086.61ms │
│ Total Time (use-yield)   │ 21271.20ms │
│ Average Time (HEAD)      │   490.39ms │
│ Average Time (use-yield) │   494.68ms │
│ Queries Faster           │          7 │
│ Queries Slower           │          7 │
│ Queries with No Change   │         29 │
│ Queries with Failure     │          0 │
└──────────────────────────┴────────────┘

Resource Usage

clickbench_partitioned — base (merge-base)

Metric Value
Wall time 110.0s
Peak memory 11.6 GiB
Avg memory 4.6 GiB
CPU user 1081.6s
CPU sys 77.2s
Peak spill 0 B

clickbench_partitioned — branch

Metric Value
Wall time 110.0s
Peak memory 12.2 GiB
Avg memory 4.6 GiB
CPU user 1085.8s
CPU sys 80.7s
Peak spill 0 B

File an issue against this benchmark runner

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark completed (GKE) | trigger

Instance: c4a-highmem-16 (12 vCPU / 65 GiB)

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected
Details

group                                               HEAD                                    use-yield
-----                                               ----                                    ---------
merge sorted f64 100k                               1.01      3.4±0.02ms        ? ?/sec     1.00      3.3±0.02ms        ? ?/sec
merge sorted f64 1M                                 1.01     34.4±0.18ms        ? ?/sec     1.00     33.9±0.21ms        ? ?/sec
merge sorted i64 100k                               1.01      3.3±0.07ms        ? ?/sec     1.00      3.3±0.01ms        ? ?/sec
merge sorted i64 1M                                 1.01     33.2±0.14ms        ? ?/sec     1.00     32.9±0.11ms        ? ?/sec
merge sorted mixed dictionary tuple 100k            1.03      7.8±0.07ms        ? ?/sec     1.00      7.6±0.04ms        ? ?/sec
merge sorted mixed dictionary tuple 1M              1.00     75.0±0.41ms        ? ?/sec     1.00     75.1±0.23ms        ? ?/sec
merge sorted mixed tuple 100k                       1.01      7.8±0.05ms        ? ?/sec     1.00      7.7±0.04ms        ? ?/sec
merge sorted mixed tuple 1M                         1.00     76.1±0.18ms        ? ?/sec     1.01     76.9±0.23ms        ? ?/sec
merge sorted mixed tuple with utf8 view 100k        1.03      7.5±0.07ms        ? ?/sec     1.00      7.2±0.07ms        ? ?/sec
merge sorted mixed tuple with utf8 view 1M          1.00     71.5±0.21ms        ? ?/sec     1.01     72.2±0.19ms        ? ?/sec
merge sorted utf8 dictionary 100k                   1.00      3.6±0.02ms        ? ?/sec     1.00      3.6±0.01ms        ? ?/sec
merge sorted utf8 dictionary 1M                     1.00     35.1±0.20ms        ? ?/sec     1.01     35.3±0.13ms        ? ?/sec
merge sorted utf8 dictionary tuple 100k             1.01      5.2±0.03ms        ? ?/sec     1.00      5.2±0.03ms        ? ?/sec
merge sorted utf8 dictionary tuple 1M               1.00     51.2±0.25ms        ? ?/sec     1.00     51.1±0.24ms        ? ?/sec
merge sorted utf8 high cardinality 100k             1.04      5.3±0.02ms        ? ?/sec     1.00      5.1±0.02ms        ? ?/sec
merge sorted utf8 high cardinality 1M               1.29   106.5±63.91ms        ? ?/sec     1.00    82.8±49.91ms        ? ?/sec
merge sorted utf8 low cardinality 100k              1.03      3.5±0.02ms        ? ?/sec     1.00      3.4±0.01ms        ? ?/sec
merge sorted utf8 low cardinality 1M                1.03     36.3±0.17ms        ? ?/sec     1.00     35.2±0.19ms        ? ?/sec
merge sorted utf8 tuple 100k                        1.03      8.4±0.07ms        ? ?/sec     1.00      8.2±0.04ms        ? ?/sec
merge sorted utf8 tuple 1M                          1.00     82.1±0.45ms        ? ?/sec     1.00     82.4±0.44ms        ? ?/sec
merge sorted utf8 view high cardinality 100k        1.10      4.7±0.04ms        ? ?/sec     1.00      4.3±0.04ms        ? ?/sec
merge sorted utf8 view high cardinality 1M          1.26    76.8±31.44ms        ? ?/sec     1.00    60.9±25.01ms        ? ?/sec
merge sorted utf8 view low cardinality 100k         1.04      2.4±0.02ms        ? ?/sec     1.00      2.4±0.01ms        ? ?/sec
merge sorted utf8 view low cardinality 1M           1.03     25.0±0.16ms        ? ?/sec     1.00     24.4±0.15ms        ? ?/sec
merge sorted utf8 view tuple 100k                   1.05      8.1±0.13ms        ? ?/sec     1.00      7.8±0.05ms        ? ?/sec
merge sorted utf8 view tuple 1M                     1.01     78.5±0.44ms        ? ?/sec     1.00     78.0±0.72ms        ? ?/sec
sort f64 100k                                       1.01      2.7±0.01ms        ? ?/sec     1.00      2.7±0.02ms        ? ?/sec
sort f64 1M                                         1.01     23.8±0.48ms        ? ?/sec     1.00     23.6±0.50ms        ? ?/sec
sort i64 100k                                       1.02      2.5±0.02ms        ? ?/sec     1.00      2.4±0.01ms        ? ?/sec
sort i64 1M                                         1.02     22.8±0.39ms        ? ?/sec     1.00     22.4±0.38ms        ? ?/sec
sort merge f64 100k                                 1.01      3.1±0.01ms        ? ?/sec     1.00      3.1±0.01ms        ? ?/sec
sort merge f64 1M                                   1.02     31.4±0.10ms        ? ?/sec     1.00     30.8±0.07ms        ? ?/sec
sort merge i64 100k                                 1.01      3.0±0.01ms        ? ?/sec     1.00      3.0±0.01ms        ? ?/sec
sort merge i64 1M                                   1.01     30.2±0.07ms        ? ?/sec     1.00     29.8±0.12ms        ? ?/sec
sort merge mixed dictionary tuple 100k              1.01      7.2±0.03ms        ? ?/sec     1.00      7.1±0.02ms        ? ?/sec
sort merge mixed dictionary tuple 1M                1.00     73.0±0.44ms        ? ?/sec     1.00     73.1±0.36ms        ? ?/sec
sort merge mixed tuple 100k                         1.00      7.2±0.05ms        ? ?/sec     1.00      7.2±0.02ms        ? ?/sec
sort merge mixed tuple 1M                           1.00     73.3±0.21ms        ? ?/sec     1.01     74.3±0.27ms        ? ?/sec
sort merge mixed tuple with utf8 view 100k          1.00      7.1±0.05ms        ? ?/sec     1.01      7.1±0.04ms        ? ?/sec
sort merge mixed tuple with utf8 view 1M            1.00     68.0±0.22ms        ? ?/sec     1.01     68.9±0.21ms        ? ?/sec
sort merge utf8 dictionary 100k                     1.01      3.1±0.01ms        ? ?/sec     1.00      3.1±0.01ms        ? ?/sec
sort merge utf8 dictionary 1M                       1.00     31.0±0.14ms        ? ?/sec     1.01     31.2±0.11ms        ? ?/sec
sort merge utf8 dictionary tuple 100k               1.01      4.8±0.03ms        ? ?/sec     1.00      4.8±0.02ms        ? ?/sec
sort merge utf8 dictionary tuple 1M                 1.00     49.5±0.26ms        ? ?/sec     1.01     49.9±0.26ms        ? ?/sec
sort merge utf8 high cardinality 100k               1.04      5.0±0.02ms        ? ?/sec     1.00      4.8±0.01ms        ? ?/sec
sort merge utf8 high cardinality 1M                 1.03     49.7±0.19ms        ? ?/sec     1.00     48.1±0.11ms        ? ?/sec
sort merge utf8 low cardinality 100k                1.03      3.3±0.01ms        ? ?/sec     1.00      3.2±0.01ms        ? ?/sec
sort merge utf8 low cardinality 1M                  1.03     33.1±0.10ms        ? ?/sec     1.00     32.0±0.14ms        ? ?/sec
sort merge utf8 tuple 100k                          1.01      8.4±0.06ms        ? ?/sec     1.00      8.3±0.04ms        ? ?/sec
sort merge utf8 tuple 1M                            1.00     80.3±0.39ms        ? ?/sec     1.01     80.8±0.44ms        ? ?/sec
sort merge utf8 view high cardinality 100k          1.09      4.5±0.05ms        ? ?/sec     1.00      4.1±0.02ms        ? ?/sec
sort merge utf8 view high cardinality 1M            1.08     43.8±0.35ms        ? ?/sec     1.00     40.7±0.35ms        ? ?/sec
sort merge utf8 view low cardinality 100k           1.05      2.2±0.01ms        ? ?/sec     1.00      2.1±0.01ms        ? ?/sec
sort merge utf8 view low cardinality 1M             1.04     21.4±0.07ms        ? ?/sec     1.00     20.7±0.12ms        ? ?/sec
sort merge utf8 view tuple 100k                     1.02      7.8±0.06ms        ? ?/sec     1.00      7.6±0.03ms        ? ?/sec
sort merge utf8 view tuple 1M                       1.00     76.1±0.43ms        ? ?/sec     1.00     76.3±0.33ms        ? ?/sec
sort mixed dictionary tuple 100k                    1.03     11.0±0.07ms        ? ?/sec     1.00     10.7±0.07ms        ? ?/sec
sort mixed dictionary tuple 1M                      1.01    148.1±1.81ms        ? ?/sec     1.00    146.0±1.49ms        ? ?/sec
sort mixed tuple 100k                               1.03     10.4±0.07ms        ? ?/sec     1.00     10.0±0.04ms        ? ?/sec
sort mixed tuple 1M                                 1.01    119.6±0.97ms        ? ?/sec     1.00    118.4±0.86ms        ? ?/sec
sort mixed tuple with utf8 view 100k                1.04      9.8±0.08ms        ? ?/sec     1.00      9.5±0.06ms        ? ?/sec
sort mixed tuple with utf8 view 1M                  1.00    112.9±0.79ms        ? ?/sec     1.00    113.2±0.82ms        ? ?/sec
sort partitioned f64 100k                           1.05  140.2±174.36µs        ? ?/sec     1.00  133.1±130.38µs        ? ?/sec
sort partitioned f64 1M                             1.07  1771.7±77.84µs        ? ?/sec     1.00  1657.1±82.48µs        ? ?/sec
sort partitioned i64 100k                           1.05  141.7±198.79µs        ? ?/sec     1.00  134.5±154.97µs        ? ?/sec
sort partitioned i64 1M                             1.12  1809.4±73.89µs        ? ?/sec     1.00  1617.1±104.07µs        ? ?/sec
sort partitioned mixed dictionary tuple 100k        1.02  534.7±273.63µs        ? ?/sec     1.00  525.0±180.76µs        ? ?/sec
sort partitioned mixed dictionary tuple 1M          1.04     11.4±0.40ms        ? ?/sec     1.00     11.0±0.17ms        ? ?/sec
sort partitioned mixed tuple 100k                   1.03  315.8±180.36µs        ? ?/sec     1.00  307.0±138.14µs        ? ?/sec
sort partitioned mixed tuple 1M                     1.01     10.0±0.29ms        ? ?/sec     1.00      9.8±0.07ms        ? ?/sec
sort partitioned mixed tuple with utf8 view 100k    1.01   876.3±94.99µs        ? ?/sec     1.00   870.9±81.73µs        ? ?/sec
sort partitioned mixed tuple with utf8 view 1M      1.02      9.1±0.27ms        ? ?/sec     1.00      9.0±0.08ms        ? ?/sec
sort partitioned utf8 dictionary 100k               1.08  179.7±288.47µs        ? ?/sec     1.00  166.2±191.79µs        ? ?/sec
sort partitioned utf8 dictionary 1M                 1.00      2.7±0.03ms        ? ?/sec     1.00      2.7±0.02ms        ? ?/sec
sort partitioned utf8 dictionary tuple 100k         1.00   460.5±95.20µs        ? ?/sec     1.01  464.6±118.64µs        ? ?/sec
sort partitioned utf8 dictionary tuple 1M           1.03     10.5±0.41ms        ? ?/sec     1.00     10.2±0.16ms        ? ?/sec
sort partitioned utf8 high cardinality 100k         1.06  199.2±277.22µs        ? ?/sec     1.00  188.4±210.98µs        ? ?/sec
sort partitioned utf8 high cardinality 1M           1.04      3.9±0.06ms        ? ?/sec     1.00      3.7±0.04ms        ? ?/sec
sort partitioned utf8 low cardinality 100k          1.02   197.4±89.58µs        ? ?/sec     1.00   194.2±71.66µs        ? ?/sec
sort partitioned utf8 low cardinality 1M            1.02      3.2±0.03ms        ? ?/sec     1.00      3.1±0.03ms        ? ?/sec
sort partitioned utf8 tuple 100k                    1.01  1152.3±127.91µs        ? ?/sec    1.00  1138.3±112.16µs        ? ?/sec
sort partitioned utf8 tuple 1M                      1.03     12.2±0.45ms        ? ?/sec     1.00     11.9±0.16ms        ? ?/sec
sort partitioned utf8 view high cardinality 100k    1.00  367.9±196.94µs        ? ?/sec     1.03  379.1±154.61µs        ? ?/sec
sort partitioned utf8 view high cardinality 1M      1.06      4.3±0.08ms        ? ?/sec     1.00      4.1±0.11ms        ? ?/sec
sort partitioned utf8 view low cardinality 100k     1.07  158.1±186.45µs        ? ?/sec     1.00  147.6±106.62µs        ? ?/sec
sort partitioned utf8 view low cardinality 1M       1.07      2.3±0.06ms        ? ?/sec     1.00      2.2±0.03ms        ? ?/sec
sort partitioned utf8 view tuple 100k               1.02   974.9±73.67µs        ? ?/sec     1.00   958.8±67.53µs        ? ?/sec
sort partitioned utf8 view tuple 1M                 1.00     10.3±0.13ms        ? ?/sec     1.00     10.3±0.12ms        ? ?/sec
sort utf8 dictionary 100k                           1.04  1188.1±43.17µs        ? ?/sec     1.00  1139.7±11.95µs        ? ?/sec
sort utf8 dictionary 1M                             1.00     27.6±0.32ms        ? ?/sec     1.00     27.5±0.32ms        ? ?/sec
sort utf8 dictionary tuple 100k                     1.02      8.1±0.05ms        ? ?/sec     1.00      7.9±0.04ms        ? ?/sec
sort utf8 dictionary tuple 1M                       1.02    112.1±1.27ms        ? ?/sec     1.00    110.1±1.00ms        ? ?/sec
sort utf8 high cardinality 100k                     1.05      3.8±0.10ms        ? ?/sec     1.00      3.6±0.05ms        ? ?/sec
sort utf8 high cardinality 1M                       1.02     56.3±1.34ms        ? ?/sec     1.00     55.1±1.29ms        ? ?/sec
sort utf8 low cardinality 100k                      1.03      3.8±0.02ms        ? ?/sec     1.00      3.7±0.02ms        ? ?/sec
sort utf8 low cardinality 1M                        1.01     37.4±0.58ms        ? ?/sec     1.00     37.1±0.74ms        ? ?/sec
sort utf8 tuple 100k                                1.05     11.0±0.10ms        ? ?/sec     1.00     10.5±0.05ms        ? ?/sec
sort utf8 tuple 1M                                  1.01    141.6±1.54ms        ? ?/sec     1.00    140.2±2.28ms        ? ?/sec
sort utf8 view high cardinality 100k                1.09      3.9±0.08ms        ? ?/sec     1.00      3.6±0.04ms        ? ?/sec
sort utf8 view high cardinality 1M                  1.06     63.7±0.89ms        ? ?/sec     1.00    59.8±11.67ms        ? ?/sec
sort utf8 view low cardinality 100k                 1.06      2.3±0.03ms        ? ?/sec     1.00      2.2±0.02ms        ? ?/sec
sort utf8 view low cardinality 1M                   1.11     28.0±0.42ms        ? ?/sec     1.00     25.1±0.51ms        ? ?/sec
sort utf8 view tuple 100k                           1.05     10.4±0.11ms        ? ?/sec     1.00     10.0±0.06ms        ? ?/sec
sort utf8 view tuple 1M                             1.01    139.0±1.14ms        ? ?/sec     1.00    137.3±1.31ms        ? ?/sec

Resource Usage

sort — base (merge-base)

Metric Value
Wall time 3275.7s
Peak memory 792.5 MiB
Avg memory 500.9 MiB
CPU user 4960.0s
CPU sys 230.7s
Peak spill 0 B

sort — branch

Metric Value
Wall time 3450.8s
Peak memory 793.6 MiB
Avg memory 465.3 MiB
CPU user 4874.3s
CPU sys 225.9s
Peak spill 0 B

File an issue against this benchmark runner

@rluvaton

rluvaton commented Jul 9, 2026

Copy link
Copy Markdown
Member Author

run benchmark sort tpch10

@adriangbot

Copy link
Copy Markdown

🤖 Benchmark running (GKE) | trigger
Instance: c4a-highmem-16 (12 vCPU / 65 GiB) | Linux bench-c4924659837-942-59phh 6.12.85+ #1 SMP Mon May 11 08:17:35 UTC 2026 aarch64 GNU/Linux

CPU Details (lscpu)
Architecture:                            aarch64
CPU op-mode(s):                          64-bit
Byte Order:                              Little Endian
CPU(s):                                  16
On-line CPU(s) list:                     0-15
Vendor ID:                               ARM
Model name:                              Neoverse-V2
Model:                                   1
Thread(s) per core:                      1
Core(s) per cluster:                     16
Socket(s):                               -
Cluster(s):                              1
Stepping:                                r0p1
BogoMIPS:                                2000.00
Flags:                                   fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma lrcpc dcpop sha3 sm3 sm4 asimddp sha512 sve asimdfhm dit uscat ilrcpc flagm sb paca pacg dcpodp sve2 sveaes svepmull svebitperm svesha3 svesm4 flagm2 frint svei8mm svebf16 i8mm bf16 dgh rng bti
L1d cache:                               1 MiB (16 instances)
L1i cache:                               1 MiB (16 instances)
L2 cache:                                32 MiB (16 instances)
L3 cache:                                80 MiB (1 instance)
NUMA node(s):                            1
NUMA node0 CPU(s):                       0-15
Vulnerability Gather data sampling:      Not affected
Vulnerability Indirect target selection: Not affected
Vulnerability Itlb multihit:             Not affected
Vulnerability L1tf:                      Not affected
Vulnerability Mds:                       Not affected
Vulnerability Meltdown:                  Not affected
Vulnerability Mmio stale data:           Not affected
Vulnerability Reg file data sampling:    Not affected
Vulnerability Retbleed:                  Not affected
Vulnerability Spec rstack overflow:      Not affected
Vulnerability Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
Vulnerability Spectre v1:                Mitigation; __user pointer sanitization
Vulnerability Spectre v2:                Mitigation; CSV2, BHB
Vulnerability Srbds:                     Not affected
Vulnerability Tsa:                       Not affected
Vulnerability Tsx async abort:           Not affected
Vulnerability Vmscape:                   Not affected

Comparing use-yield (18262df) to b790763 (merge-base) diff using: sort
Results will be posted here when complete


File an issue against this benchmark runner

rluvaton added 2 commits July 9, 2026 19:33
# Conflicts:
#	datafusion/physical-plan/src/sorts/merge.rs
@rluvaton
rluvaton marked this pull request as ready for review July 9, 2026 16:34
let streams =
FieldCursorStream::<$t>::new($sort, $streams, $reservation.new_empty());
return Ok(Box::pin(SortPreservingMergeStream::new(
return Ok(SortPreservingMergeStream::new(

@pepijnve pepijnve Jul 9, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since SortPreservingMergeStream no longer has a Stream implementation and you need to turn it into a stream, we might want to give it a different name.

Would it be possible to return the impl Stream directly from new to avoid the somewhat odd construct?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since SortPreservingMergeStream is no longer has a Stream implementation and you need to turn it into a stream, we might want to give it a different name.

Would it be possible to return the impl Stream directly from new to avoid the somewhat odd construct?

I wanted to reduce the amount of changes in this PR as possible so it will be easier to review and see the actual difference between generators and current implementation.

this can be a followup PR

Comment thread Cargo.toml Outdated
Comment thread datafusion/physical-plan/src/sorts/merge.rs Outdated
@rluvaton

Copy link
Copy Markdown
Member Author

@mbutrovich I think implementing SMJ with generators will simplify the code greatly and may even improve perf

@rluvaton

Copy link
Copy Markdown
Member Author

@Jefffrey can you please review?

@alamb alamb left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this proposal @rluvaton and @pepijnve and @stuhood

I agree with @stuhood and @pepijnve that this change while it may look simpler is subject to some opinions about if wrapping the complexity in another crate which is not widely used

I also agree with @rluvaton that the SortPreservingMerge code is about as complicated as it can get and still be undersrtandable without some refactoring -- so to make progress we will have to refactor it (basically what @Rachelint @2010YOUY01 and I are doing to the aggregate code in #22710)

One thing I think helps is separting the stream control flow (aka the poll_next implementations) from the actual logic (aka messing around with data).

A major win of this PR for simplicity I think is that it moves the logic of updating the Loser tree implementation out of the control logic. Rather than using a new crate / control flow pattern, we could instead try moving the loser tree implementation into its own struct (encapsulate the logic and make the boundaries of the different responsibilities clearer, and make the control flow easier to read)

Comment thread Cargo.toml Outdated
Comment thread datafusion/physical-plan/src/sorts/merge.rs Outdated
Comment thread datafusion/physical-plan/src/sorts/merge.rs Outdated
@pepijnve

pepijnve commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

One thing I think helps is separting the stream control flow (aka the poll_next implementations) from the actual logic (aka messing around with data).

Tooting my own horn a bit, but could you take a quick peek at #23530 https://github.com/pepijnve/datafusion/blob/use_yield_alternative/datafusion/execution/src/async_stream.rs
Is that what you mean or do you see some other way to extract the logic?

pull Bot pushed a commit to TCeason/arrow-datafusion that referenced this pull request Jul 13, 2026
## Which issue does this PR close?

None, related to PR apache#23407

## Rationale for this change

Manually writing `Stream` implementations can be quite tedious since it
requires implementing the state machine of the stream yourself. This
often results in hard to read code. The same problem exists with manual
`Future` implementations and `async` was added to the Rust language to
mitigate exactly this problem. Unfortunately there's no language level
support yet to help with writing streams/generators.

There are quite a few projects that attempt to fill this gap:
- Tokio's
[async_stream](https://docs.rs/async-stream/latest/async_stream/)
provides a proc macro that recognises a `yield` keyword. This is a good
implementation, but proc macros don't play nice with code formatting,
increase compile time, and in this particular case prevent decomposition
into smaller functions.
-
[async_fn_stream](https://docs.rs/async-fn-stream/latest/async_fn_stream/)
provides an implementation of the same concept, but without the proc
macro. Unfortunately this implementation chooses a heavier mechanism to
communicate generated values back to the stream via a `SmallVec`.
-
[genawaiter](https://docs.rs/genawaiter/latest/genawaiter/sync/index.html)
is a more general purpose generator library, but this can also be used
to implement `Stream`s. This project does miss some of the ergonomics
provided by the other two in the form of `try_` variants that help in
implementing fallible streams.

Since none of these variants seems like the ideal candidate, the best
option might be to have a custom implementation of the concept tailored
to the needs of the DataFusion project. This PR provides an initial
draft of exactly that.

## What changes are included in this PR?

- Adds `async_stream` and `async_try_stream` functions that create
Stream implementations based on an async generator function.
 
The initial implementation was inspired by the macro expansion produced
by `async_stream`. The code was then adapted further taking inspiration
from the two other libraries. Specifically, the `Emitter` terminology
was taken from `async_fn_stream` and the `Arc<Mutex<Option<T>>>` value
transfer mechanism was taken from `genawaiter`.

`async_stream` uses a very light weight thread-local storage based
mechanism to handle value transfer, but this felt too risky to use when
the emitter is exposed. It makes sense in the Tokio implementation since
the proc macro can manage control flow in a stricter way.

I wasn't entirely sure if taking some inspiration from has code
licensing implications. I applied ASLv2 for now on the added code.

## Are these changes tested?

Test code was mainly adapted from the tokio implementation.

## Are there any user-facing changes?

Yes, new public function `async_stream` and `async_try_stream`

---------

Co-authored-by: Raz Luvaton <16746759+rluvaton@users.noreply.github.com>

@stuhood stuhood left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

@rluvaton

Copy link
Copy Markdown
Member Author

@2010YOUY01 @Rachelint you might want to consider using the generator to simplify the aggregate rewrite

@2010YOUY01

Copy link
Copy Markdown
Contributor

@2010YOUY01 @Rachelint you might want to consider using the generator to simplify the aggregate rewrite

Yes this makes sense, I'll give it a try later.

I also agree with @rluvaton that the SortPreservingMerge code is about as complicated as it can get and still be undersrtandable without some refactoring -- so to make progress we will have to refactor it (basically what @Rachelint @2010YOUY01 and I are doing to the aggregate code in #22710)

One thing I think helps is separting the stream control flow (aka the poll_next implementations) from the actual logic (aka messing around with data).

A major win of this PR for simplicity I think is that it moves the logic of updating the Loser tree implementation out of the control logic. Rather than using a new crate / control flow pattern, we could instead try moving the loser tree implementation into its own struct (encapsulate the logic and make the boundaries of the different responsibilities clearer, and make the control flow easier to read)

I have similar opinions to @alamb on how to reduce complexity in many existing operators, I’ll try to explain them a little differently.

To make an operator implementation easy to read, its entry point should look like pseudocode:

# Ideal shape of aggregation
# aggregate_hash_table stores: group_keys -> group_states (with all internal details encapsulated)
for batch in input_stream:
    aggregate_hash_table.push(batch)

output_stream = aggregate_hash_table.finish()

for batch in output_stream:
    yield batch

There are two major gaps between this ideal and the current implementation:

  1. The yield-based pattern is difficult to express using the existing streaming interface. (this PR is trying to improve)
  2. Most implementations directly manipulate low-level primitives—such as vectors, batches, and flags—in their main control flow.

Point 2 causes an issue: in order to read the code, at the same time, we have to deal with the complexity for both control flow and logic details around low-level primitives. This causes huge cognitive load.

A better approach would be to encapsulate these details in a deeper module, and implement the core logic around that deep module. The goal is to make the entry-point code look as much like pseudocode as possible—e.g. the aggregate_hash_table abstraction above. This gives readers a clear abstraction boundary: they can understand the overall control flow first, then examine the implementation details only when needed.

I think the second issue is the larger source of complexity, but it's often overlooked.

@rluvaton

Copy link
Copy Markdown
Member Author

@2010YOUY01 My goal for simplifying here and in other places is to make the code looks as similar as textbook psuedo code as possible and abstracting out all the implementation detail of rust and arrow.

for example merge sort is pretty basic in the idea, and as such the code should look basic at first glance.

@2010YOUY01 Are you opposed to having this PR?

@Weijun-H Weijun-H left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@rluvaton
rluvaton added this pull request to the merge queue Jul 15, 2026
Merged via the queue into apache:main with commit 096012e Jul 15, 2026
40 checks passed
@rluvaton
rluvaton deleted the use-yield branch July 15, 2026 10:15
@alamb

alamb commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Thanks for moving this code forward everyone

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

physical-plan Changes to the physical-plan crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants